/*
 * Copyright (c) www.bugull.com
 */

package com.bugull.farm.core.client;

import com.bugull.farm.core.cache.PropertiesCache;
import com.bugull.farm.core.utils.ByteUtil;
import com.bugull.farm.core.utils.StringUtil;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.logging.log4j.*;

/**
 * Client that connect to BuguKeeper using UDP.
 *
 * BuguKeeper records every device activation information, such as:
 * projectCode, companyCode, deviceType and activation time.
 *
 * @author Frank Wen(xbwen@hotmail.com)
 */
public class BuguKeeperClient {

    private final static Logger logger = LogManager.getLogger(BuguKeeperClient.class);

    private ExecutorService executor;

    private SocketAddress address;

    private BuguKeeperClient(){
        executor = Executors.newSingleThreadExecutor();
        address = new InetSocketAddress(PropertiesCache.getInstance().get("bugu.keeper.host"), PropertiesCache.getInstance().getInt("bugu.keeper.port"));
    }

    private static class Holder {
        final static BuguKeeperClient instance = new BuguKeeperClient();
    }

    public static BuguKeeperClient getInstance(){
        return Holder.instance;
    }

    public void reportActivation(String project, byte[] mac, byte companyCode, byte deviceType){
        if(StringUtil.isEmpty(project)){
            return;
        }
        if(project.length()!=2 || mac.length!=6){
            return;
        }
        byte[] projectCode = project.getBytes();
        ReportActivationTask task = new ReportActivationTask(projectCode, mac, companyCode, deviceType);
        executor.execute(task);
    }

    private class ReportActivationTask implements Runnable {

        private byte[] data;

        ReportActivationTask(byte[] projectCode, byte[] mac, byte companyCode, byte deviceType){
            data = new byte[PropertiesCache.getInstance().getInt("bugu.keeper.data.length")];
            //1 byte header
            data[0] = PropertiesCache.getInstance().getByte("bugu.keeper.head");
            //2 bytes project code
            data[1] = projectCode[0];
            data[2] = projectCode[1];
            //6 bytes mac address
            data[3] = mac[0];
            data[4] = mac[1];
            data[5] = mac[2];
            data[6] = mac[3];
            data[7] = mac[4];
            data[8] = mac[5];
            //1 byte company code
            data[9] = companyCode;
            //1 byte device type
            data[10] = deviceType;
            //1 byte checksum
            data[11] = ByteUtil.xor(data, 0, 11);
        }

        @Override
        public void run(){
            DatagramSocket socket = null;
            try{
                socket = new DatagramSocket();
                socket.setBroadcast(false);
                DatagramPacket packet = new DatagramPacket(data, data.length, address);
                socket.send(packet);
            }catch(Exception ex){
                logger.error(ex.getMessage(), ex);
            }finally{
                if(socket != null){
                    try{
                        socket.close();
                    }catch(Exception ex){
                        logger.error(ex.getMessage(), ex);
                    }
                }
            }
        }
    }

}
